﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Contracts;
using Events;
using Model;
using Tools;

namespace ViewModel
{
    public class MainViewModel : ApplicationViewModel
    {
        #region commands to be called from the view
        public ICommand LoginCommand { get; private set; }
        public ICommand SelectContactCommand { get; private set; }
        #endregion

        #region events for the view
        // events for view
        public delegate void ImageUpdatedHandler(object sender, EventArgs e);
        public static event ImageUpdatedHandler OnImageUpdated;

        public delegate void UserConnectedHandler(object sender, RoutedEventArgs e);
        public static event UserConnectedHandler OnUserConnected;

        public delegate void ShowDiscussionContainerHandler(object sender, EventArgs e);
        public static event ShowDiscussionContainerHandler OnShowDiscussionContainer;

        public delegate void ContactUpdatedHandler(object sender, TextEventArgs e);
        public static event ContactUpdatedHandler OnContactUpdated;

        #endregion

        #region Accessors / Properties
        private ObservableCollection<Contact> contactList;
        private String login;
        private String password;
        private Boolean loginValid = false;
        private Boolean pwdValid = false;
        private ImageSource img;
        public ObservableCollection<Contact> ContactList
        {
            get { return this.contactList; }
        }

        public ImageSource Img
        {   
            get
                {
                    return this.img;           
                }
            set
            {
                this.img = value; 
                OnImageUpdated(this, new EventArgs());
            }
        }
        private User currentUser;
        public User CurrentUser
        {
            get
            {
                return this.currentUser;
            } 
            set
            {
                this.currentUser = value;
                OnPropertyChanged("Nickname");
                OnPropertyChanged("Status");
            }
        }

        public String Nickname
        {
            get
            {
                return this.CurrentUser.Nickname;
            }
            set
            {
                this.currentUser.Nickname = value;
                this.getModel.UpdateUser(this.currentUser);
            }
        }
        public Contact SelectedContact { get; set; }
        
        public string Login{
            get
            {
                return login; 
            }

            set
            {
               /* if (String.IsNullOrEmpty(value) || !(value.Contains("@")))
                    throw new Exception("Login Invalid");*/

                login = value;
                loginValid = true;
            }
        }

        public string Password
        {
            get
            {
                return password;
            }

            set
            {
                /*if (String.IsNullOrEmpty(value) || (value.Length < 6))
                    throw new Exception("Password Invalid");*/

                password = value;
                pwdValid = true;
            }
        }

        public bool CreateAccount { get; set; }
        #endregion

        /// <summary>
        /// At the beginning, create some commands
        /// and initialize the contactlist
        /// </summary>
        public MainViewModel()
        {
            this.contactList = new ObservableCollection<Contact>();
            LoginCommand = new DelegateCommand(p => Connection());
            SelectContactCommand = new DelegateCommand(p => OpenDiscussion(p as Contact));

        }

        /// <summary>
        /// Try to use the current login and password to 
        /// connect the chat.
        /// 
        /// Create an account if needed.
        /// </summary>
        public void Connection()
        {
            if (loginValid && pwdValid)
            {
                if (CreateAccount)
                {
                    getModel.AddUser(login, password);
                }

                if (getModel.Login(login, password))
                {   
                    this.setContactList();
                    this.waitForMessages();
                    this.waitForNotifications();
                    this.setUser();
                    OnUserConnected(this, new RoutedEventArgs());
                    this.Img = GestionImage.ImageToImageSource(getModel.GetAvatar((this.CurrentUser.Mail)));
                }
            }
        }

        private void waitForNotifications()
        {
            this.getModel.OnContactChange += DisplayNotification;
        }

        private void DisplayNotification(object sender, ContactEventArgs e)
        {
            var contact = (from c in this.ContactList
                           where c.Mail.Equals(e.contact.Mail)
                           select c).FirstOrDefault();
            
            if (contact == null)
                return;
            Status tempStatus = contact.Status;
            contact.Status = e.contact.Status;
            contact.Nickname = e.contact.Nickname;
            this.filterContactInfos(contact);
            if (!tempStatus.Equals(contact.Status))
                OnContactUpdated(this, new TextEventArgs(String.Format("\"{0}\" is now {1}", contact.Nickname, e.contact.Status.ToString())));
        }

        public void Logout()
        {
            this.getModel.Logout();
        }

        /// <summary>
        /// Get the user from Model
        /// </summary>
        private void setUser()
        {
            this.CurrentUser = getModel.GetUser();
        }

        private void waitForMessages()
        {
            this.getModel.OnUserMessageReceived += DisplayUserMessage;
        }

        private void DisplayUserMessage(object sender, UserMessageEventArgs e)
        {
            DiscussionContainerViewModel dc = DiscussionContainerViewModel.getInstance();
            //OnShowDiscussionContainer(this, new EventArgs());
            dc.DisplayMessage(e.Message);
        }

        private void OpenDiscussion(Contact contact)
        {
            DiscussionContainerViewModel dc = DiscussionContainerViewModel.getInstance();
            dc.AddDiscussion(contact);
        }

        private void setContactList()
        {
            // First, clear the contact list
            this.ContactList.Clear();
            // Then add the items
            foreach (Contact contact in this.getModel.GetContacts())
            {
                this.filterContactInfos(contact);
                this.contactList.Add(contact);
            }
        }

        private void filterContactInfos(Contact contact)
        {
            if (contact.Alias.Equals(""))
            {
                if (contact.Nickname.Equals(""))
                {
                    contact.Alias = contact.Mail;
                }
                else
                {
                    contact.Alias = contact.Nickname;
                }
            }
        }

        public void RefreshContactList()
        {
            this.setContactList();
        }

        public void DeleteContact(Contact theContact)
        {
            this.getModel.DeleteContact(theContact.Mail);
            this.ContactList.Remove(theContact);
        }
    }
}